// 阿里云SenseVoice语音识别服务
// 集成本地下载和OSS上传功能，确保音频文件公网可访问
import AliyunOSSService from './aliyunOSS'
import FileManager from './fileManager'

interface SenseVoiceTask {
  task_id: string
  task_status: 'PENDING' | 'RUNNING' | 'SUCCEEDED' | 'FAILED'
  submit_time?: string
  scheduled_time?: string
  end_time?: string
  results?: Array<{
    file_url: string
    transcription_url?: string
    subtask_status: 'PENDING' | 'RUNNING' | 'SUCCEEDED' | 'FAILED'
    code?: string
    message?: string
  }>
  task_metrics?: {
    TOTAL: number
    SUCCEEDED: number
    FAILED: number
  }
}

interface SenseVoiceResponse {
  request_id: string
  code?: string
  message?: string
  output: SenseVoiceTask
  usage?: {
    duration: number
  }
}

interface TranscriptionResult {
  file_url: string
  properties: {
    audio_format: string
    channels: number[]
    original_sampling_rate: number
    original_duration_in_milliseconds: number
  }
  transcripts: Array<{
    channel_id: number
    content_duration_in_milliseconds: number
    text: string
    sentences: Array<{
      begin_time: number
      end_time: number
      text: string
    }>
  }>
}

class AliyunSenseVoiceService {
  private apiKey: string
  private baseUrl = 'https://dashscope.aliyuncs.com/api/v1/services/audio/asr/transcription'
  private ossService: AliyunOSSService | null = null
  private fileManager: FileManager

  constructor(apiKey?: string) {
    this.apiKey = apiKey || process.env.DASHSCOPE_API_KEY || ''
    if (!this.apiKey) {
      throw new Error('DashScope API Key is required. Please set DASHSCOPE_API_KEY environment variable.')
    }

    // 初始化文件管理器
    this.fileManager = new FileManager()
    console.log('文件管理器初始化成功')

    // 初始化OSS服务（如果配置了的话）
    try {
      this.ossService = new AliyunOSSService()
      console.log('OSS服务初始化成功')
    } catch (error) {
      console.warn('OSS服务初始化失败，将直接使用原始URL:', error instanceof Error ? error.message : 'Unknown error')
      this.ossService = null
    }
  }

  /**
   * 预处理音频文件：下载到本地 -> 上传到OSS -> 获得公网URL
   * @param fileUrls 原始音频文件URL列表
   * @returns 处理后的URL列表和清理函数
   */
  private async preprocessAudioFiles(fileUrls: string[]): Promise<{
    processedUrls: string[]
    cleanup: () => Promise<void>
    uploadedKeys: string[]
    localFilePaths: string[]
  }> {
    const processedUrls: string[] = []
    const uploadedKeys: string[] = []
    const localFilePaths: string[] = []

    if (!this.ossService) {
      // 如果没有配置OSS，直接返回原始URL
      console.log('OSS未配置，将直接使用原始URL')
      return {
        processedUrls: fileUrls,
        cleanup: async () => {},
        uploadedKeys: [],
        localFilePaths: []
      }
    }

    try {
      // 第一步：下载音频文件到本地
      console.log('🔄 第一步：下载音频文件到本地...', fileUrls.length, '个文件')
      const downloadResults = await this.fileManager.batchDownloadFromUrls(fileUrls)
      console.log('📥 下载结果:', downloadResults.map(r => ({ success: r.success, error: r.error })))

      // 第二步：将本地文件上传到OSS
      console.log('🔄 第二步：上传本地文件到OSS...')
      const successfulDownloads = downloadResults.filter(result => result.success && result.filePath)
      console.log('✅ 成功下载的文件数量:', successfulDownloads.length)

      if (successfulDownloads.length === 0) {
        console.warn('没有成功下载的文件，使用原始URL')
        return {
          processedUrls: fileUrls,
          cleanup: async () => {},
          uploadedKeys: [],
          localFilePaths: []
        }
      }

      // 准备上传数据
      const localFiles = successfulDownloads.map(result => result.filePath!)
      const originalUrls = fileUrls.slice(0, successfulDownloads.length)

      // 上传到OSS
      const uploadResults = await this.ossService.batchUploadFromLocalFiles(localFiles, originalUrls, 'sensevoice-audio')

      // 处理结果
      for (let i = 0; i < fileUrls.length; i++) {
        const downloadResult = downloadResults[i]

        if (downloadResult.success && downloadResult.filePath) {
          localFilePaths.push(downloadResult.filePath)

          // 查找对应的上传结果
          const uploadIndex = successfulDownloads.findIndex(r => r.filePath === downloadResult.filePath)
          const uploadResult = uploadIndex >= 0 ? uploadResults[uploadIndex] : null

          if (uploadResult?.success && uploadResult.url && uploadResult.key) {
            processedUrls.push(uploadResult.url)
            uploadedKeys.push(uploadResult.key)
            console.log(`音频处理成功: ${fileUrls[i]} -> 本地: ${downloadResult.filePath} -> OSS: ${uploadResult.url}`)
          } else {
            // OSS上传失败，使用原始URL
            processedUrls.push(fileUrls[i])
            console.warn(`OSS上传失败，使用原始URL: ${fileUrls[i]}, 错误: ${uploadResult?.error}`)
          }
        } else {
          // 下载失败，使用原始URL
          processedUrls.push(fileUrls[i])
          console.warn(`文件下载失败，使用原始URL: ${fileUrls[i]}, 错误: ${downloadResult.error}`)
        }
      }

    } catch (error) {
      console.error('音频文件预处理失败:', error)
      // 出错时使用原始URL
      return {
        processedUrls: fileUrls,
        cleanup: async () => {},
        uploadedKeys: [],
        localFilePaths: []
      }
    }

    // 返回清理函数
    const cleanup = async () => {
      // 保留OSS文件，不删除（用于后续访问和管理）
      if (uploadedKeys.length > 0) {
        console.log('OSS文件已保存，不删除:', uploadedKeys.length, '个文件')
        console.log('OSS文件路径:', uploadedKeys)
      }

      // 保留本地文件到downloads目录，不删除
      if (localFilePaths.length > 0) {
        console.log('本地文件已保存到downloads目录，不删除:', localFilePaths.length, '个文件')
      }
    }

    return {
      processedUrls,
      cleanup,
      uploadedKeys,
      localFilePaths
    }
  }

  /**
   * 提交语音识别任务
   * @param fileUrls 音频文件URL列表（必须是公网可访问的URL）
   * @param languageHints 语言提示，默认为自动检测
   * @param disfluencyRemovalEnabled 是否过滤语气词
   * @returns 任务响应
   */
  async submitTask(
    fileUrls: string[],
    languageHints: string[] = ['auto'],
    disfluencyRemovalEnabled: boolean = false
  ): Promise<SenseVoiceResponse> {
    // 根据文档，正确的请求体格式
    const requestBody = {
      model: 'sensevoice-v1',
      input: {
        file_urls: fileUrls
      },
      parameters: {
        language_hints: languageHints,
        disfluency_removal_enabled: disfluencyRemovalEnabled
      }
    }

    try {
      console.log('Submitting SenseVoice task:', JSON.stringify(requestBody, null, 2))

      const response = await fetch(this.baseUrl, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
          'X-DashScope-Async': 'enable'
        },
        body: JSON.stringify(requestBody)
      })

      const responseText = await response.text()
      console.log('SenseVoice API response status:', response.status)
      console.log('SenseVoice API response:', responseText)

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText} - ${responseText}`)
      }

      const result: SenseVoiceResponse = JSON.parse(responseText)

      // 确保响应结构正确
      if (!result.output) {
        throw new Error(`Invalid API response structure: ${responseText}`)
      }

      return result
    } catch (error) {
      console.error('Submit SenseVoice task error:', error)
      throw error
    }
  }

  /**
   * 查询任务状态
   * @param taskId 任务ID
   * @returns 任务状态响应
   */
  async queryTask(taskId: string): Promise<SenseVoiceResponse> {
    try {
      console.log('Querying SenseVoice task:', taskId)

      const response = await fetch(`https://dashscope.aliyuncs.com/api/v1/tasks/${taskId}`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiKey}`
        }
      })

      const responseText = await response.text()
      console.log('Query response status:', response.status)
      console.log('Query response:', responseText)

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText} - ${responseText}`)
      }

      const result: SenseVoiceResponse = JSON.parse(responseText)
      return result
    } catch (error) {
      console.error('Query SenseVoice task error:', error)
      throw error
    }
  }

  /**
   * 等待任务完成
   * @param taskId 任务ID
   * @param maxWaitTime 最大等待时间（毫秒），默认10分钟
   * @param pollInterval 轮询间隔（毫秒），默认5秒
   * @returns 完成的任务响应
   */
  async waitForCompletion(
    taskId: string,
    maxWaitTime: number = 10 * 60 * 1000, // 10分钟
    pollInterval: number = 5000 // 5秒
  ): Promise<SenseVoiceResponse> {
    const startTime = Date.now()

    while (Date.now() - startTime < maxWaitTime) {
      const response = await this.queryTask(taskId)

      if (response.output.task_status === 'SUCCEEDED' || response.output.task_status === 'FAILED') {
        return response
      }

      // 等待下次轮询
      await new Promise(resolve => setTimeout(resolve, pollInterval))
    }

    throw new Error(`Task ${taskId} did not complete within ${maxWaitTime}ms`)
  }

  /**
   * 获取识别结果
   * @param transcriptionUrl 识别结果URL
   * @returns 识别结果
   */
  async getTranscriptionResult(transcriptionUrl: string): Promise<TranscriptionResult> {
    try {
      const response = await fetch(transcriptionUrl)
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`)
      }

      const result: TranscriptionResult = await response.json()
      return result
    } catch (error) {
      console.error('Get transcription result error:', error)
      throw error
    }
  }

  /**
   * 提取纯文本内容（去除音频事件标记和情感标记）
   * @param text 原始识别文本
   * @returns 清理后的文本
   */
  cleanTranscriptionText(text: string): string {
    // 移除音频事件标记，如 <|Speech|>, <|/Speech|>, <|Applause|>, <|/Applause|> 等
    let cleanText = text.replace(/<\|[^|]*\|>/g, '')
    
    // 移除情感标记，如 |HAPPY|, |SAD|, |ANGRY|, |NEUTRAL| 等
    cleanText = cleanText.replace(/\|[A-Z_]+\|/g, '')
    
    // 移除多余的空格
    cleanText = cleanText.replace(/\s+/g, ' ').trim()
    
    return cleanText
  }

  /**
   * 一站式语音识别：预处理文件 -> 提交任务 -> 等待完成 -> 获取结果 -> 清理临时文件
   * @param fileUrls 音频文件URL列表
   * @param languageHints 语言提示
   * @param disfluencyRemovalEnabled 是否过滤语气词
   * @returns 识别结果列表
   */
  async transcribeAudio(
    fileUrls: string[],
    languageHints: string[] = ['auto'],
    disfluencyRemovalEnabled: boolean = false
  ): Promise<Array<{
    fileUrl: string
    success: boolean
    text?: string
    cleanText?: string
    duration?: number
    error?: string
    transcriptionResult?: TranscriptionResult
  }>> {
    let cleanup: (() => Promise<void>) | null = null

    try {
      // 1. 预处理音频文件（下载到本地 -> 上传到OSS）
      console.log('预处理音频文件...')
      const { processedUrls, cleanup: cleanupFn, localFilePaths } = await this.preprocessAudioFiles(fileUrls)
      cleanup = cleanupFn

      console.log(`预处理完成，本地文件: ${localFilePaths.length}个，处理后URL: ${processedUrls.length}个`)

      // 2. 提交任务
      console.log('Submitting SenseVoice task for processed files:', processedUrls)
      const submitResponse = await this.submitTask(processedUrls, languageHints, disfluencyRemovalEnabled)

      // 检查响应是否有错误
      if (!submitResponse.output || !submitResponse.output.task_id) {
        const errorMessage = submitResponse.message || submitResponse.code || 'Invalid response structure'
        throw new Error(`Submit task failed: ${errorMessage}`)
      }

      const taskId = submitResponse.output.task_id
      console.log('Task submitted with ID:', taskId)

      // 3. 等待任务完成
      console.log('Waiting for task completion...')
      const completedResponse = await this.waitForCompletion(taskId)
      
      if (completedResponse.output.task_status === 'FAILED') {
        throw new Error('Task failed to complete')
      }

      // 4. 处理结果
      const results = []

      if (completedResponse.output.results) {
        for (let i = 0; i < completedResponse.output.results.length; i++) {
          const result = completedResponse.output.results[i]
          const originalUrl = fileUrls[i] // 使用原始URL作为标识

          if (result.subtask_status === 'SUCCEEDED' && result.transcription_url) {
            try {
              // 获取详细识别结果
              const transcriptionResult = await this.getTranscriptionResult(result.transcription_url)

              // 提取文本
              const fullText = transcriptionResult.transcripts
                .map(t => t.text)
                .join(' ')

              const cleanText = this.cleanTranscriptionText(fullText)

              results.push({
                fileUrl: originalUrl, // 返回原始URL
                success: true,
                text: fullText,
                cleanText,
                duration: transcriptionResult.properties.original_duration_in_milliseconds,
                transcriptionResult
              })
            } catch (error) {
              results.push({
                fileUrl: originalUrl,
                success: false,
                error: error instanceof Error ? error.message : 'Unknown error'
              })
            }
          } else {
            results.push({
              fileUrl: originalUrl,
              success: false,
              error: result.message || 'Subtask failed'
            })
          }
        }
      }

      // 5. 清理临时文件
      if (cleanup) {
        await cleanup()
      }

      return results
    } catch (error) {
      // 确保在出错时也清理临时文件
      if (cleanup) {
        try {
          await cleanup()
        } catch (cleanupError) {
          console.error('清理临时文件失败:', cleanupError)
        }
      }

      console.error('Transcribe audio error:', error)
      throw error
    }
  }

  /**
   * 检测语言
   * @param text 识别结果文本
   * @returns 检测到的语言代码
   */
  detectLanguage(text: string): string {
    // 简单的语言检测逻辑
    const chineseRegex = /[\u4e00-\u9fff]/
    const englishRegex = /[a-zA-Z]/
    
    const chineseCount = (text.match(chineseRegex) || []).length
    const englishCount = (text.match(englishRegex) || []).length
    
    if (chineseCount > englishCount) {
      return 'zh'
    } else if (englishCount > 0) {
      return 'en'
    } else {
      return 'auto'
    }
  }
}

export default AliyunSenseVoiceService
export type { SenseVoiceResponse, TranscriptionResult }
